#include <framework/framework_i.h>

uint32_t initial_ctx_stacks[LAPIC_COUNT];
extern void __context_switch(uint32_t *from_esp, uint32_t *from_pc, uint32_t to_esp, uint32_t to_pc);
extern void __context_init(void);

int
context_init(void)
{	 
	 return 0;
}

static void
__context_deadend(struct context_s *ctx)
{
	 while (1) ;
}

void
context_fill(struct context_s *ctx, void (*entry)(void *arg), void *arg, physaddr_t vpt, uintptr_t stk_top)
{
	 if (ctx->lcpu == -1) ctx->lcpu = lcpu_id;
	 
	 ctx->vpt     = vpt;
	 ctx->stk_top = stk_top;
	 ctx->stk_ptr = ctx->stk_top;
	 
	 ctx->stk_ptr -= sizeof(void *);
	 *(void **)ctx->stk_ptr = ctx;

	 ctx->stk_ptr -= sizeof(void *);
	 *(void **)ctx->stk_ptr = NULL;

	 ctx->stk_ptr -= sizeof(uintptr_t);
	 *(uintptr_t *)ctx->stk_ptr = 0;
	 uintptr_t ebp = ctx->stk_ptr;

	 ctx->stk_ptr -= sizeof(void *);
	 *(void **)ctx->stk_ptr = arg;

	 ctx->stk_ptr -= sizeof(void *);
	 *(void **)ctx->stk_ptr = &__context_deadend;

	 ctx->stk_ptr -= sizeof(void *);
	 *(void **)ctx->stk_ptr = entry;

	 ctx->pc = (uintptr_t)__context_init;
}

void
context_switch(struct context_s *old, struct context_s *to)
{
	 lcpu_set_kstack_top(to->lcpu, to->stk_top);
	 lcpu_set_vpt_delay(to->lcpu, to->vpt);

	 if (old != NULL)
	 {
		  __context_switch(&old->stk_ptr, &old->pc, to->stk_ptr, to->pc);
	 }
	 else
	 {
		  uint32_t __unused;
		  __context_switch(&__unused, &__unused, to->stk_ptr, to->pc);
	 }
}
